import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Semaphore;


@SuppressWarnings("unchecked")
public class PlanificadorClientes extends Thread {

	private final String idPlanificador;
	private boolean prendido = true;
	
	/*
	 * Niveles del Planificador:
	 * 		- 1er nivel: Array de 4 de largo.
	 * 		- 2do nivel: Colas infinitas (dependen de 
	 * 						cuantos Clientes tengan).
	 */
	private Queue<Cliente>[] nivelesPlanif = new Queue[2];
	
	private Semaphore clientes = new Semaphore(0);
	
	public PlanificadorClientes(String idPlanificador)
	{
		this.idPlanificador = idPlanificador;
		
		for (int i = 0; i < 4; i++)
		{
			/*
			 * Crea las colas en los diferentes
			 * niveles del planificador.
			 */
			Queue<Cliente> colaClientes = new LinkedList<Cliente>();
			nivelesPlanif[i] = colaClientes;
		}
	}
	
	public String getIdPlanificador() {
		return idPlanificador;
	}
	
	public Semaphore getCliente() {
		return clientes;
	}

	public void apagar() {
		while (clientes.hasQueuedThreads())
		{
			clientes.release();
		}
		this.prendido = false;
	}
	
	/**
	 * Inserta los Clientes en el planificador y lo planifica.
	 * Dependiendo el tipo de Cliente, en que nivel del planificador
	 * lo inserta.
	 * 
	 * @param Cliente	El Cliente a planificar
	 */
	public void planificarCliente(Cliente cliente){
		try {
			synchronized (this) {
					if (cliente.EsEspecial())
					{
						nivelesPlanif[0].add(cliente);
					} else {
						nivelesPlanif[1].add(cliente);
					}
				}
				clientes.release();	//Avisa que ya hay clientes en el 
									// planificador para que se puedan
									// asignar a los Vendedores.
		} catch (Exception e) {
		}
	}
	
	/**
	 * Devuelve el Cliente de mayor prioridad, es decir
	 * el que se encuentra en la primer cola.
	 * En caso de no haber Clientes en esa cola, busca el 
	 * siguiente Cliente de mayor prioridad.
	 * 
	 * PRECONDICION: El planificador NO se encuentra
	 * vacio.
	 * 
	 * @return	Un Cliente
	 */
	public Cliente AtenderCliente(){
		try {
			clientes.acquire();	//Si no hay clientes en el planificador
								// se bloquea hasta que haya.
			
			synchronized (this) {
				Cliente p;
				int pos;
				if (nivelesPlanif[0].isEmpty())
				{
					int i = 1;
					while (i < nivelesPlanif.length)
					{
						if (!nivelesPlanif[i].isEmpty())
						{
							p = nivelesPlanif[i].remove();
							
							//pos = buscarPosCliente(p);
							//tiemposClientes.remove(pos).pararTiempo();
							//guiPlanificador.cargarPlanificador(this.nivelesPlanif);
							
							return p;
						}
						i++;
					}
				} else {
					p = nivelesPlanif[0].remove();
					
					//pos = buscarPosCliente(p);
					//tiemposClientes.remove(pos).pararTiempo();
					//guiPlanificador.cargarPlanificador(this.nivelesPlanif);
					
					return p;
				}
			}
		} catch (Exception e) {
		}
		return null;
	}
	
	/**
	 * Verifica si el planificador tiene algun Cliente adentro.
	 * 
	 * @return true si esta vacio.
	 */
	private synchronized boolean estaVacio()
	{
		boolean vacio = true;
		int i = 0;
		while ((vacio == true) && (i < nivelesPlanif.length))
		{
			if(!nivelesPlanif[i].isEmpty())
			{
				vacio = false;
			}
			i++;
		}
		return vacio;
	}
}
